package info.hexin.mvc.handler.process;

import info.hexin.lang.Strings;
import info.hexin.log.Log;
import info.hexin.log.Logs;
import info.hexin.mvc.annotation.HeaderParam;
import info.hexin.mvc.annotation.MultiFile;
import info.hexin.mvc.annotation.Param;
import info.hexin.mvc.annotation.PathParam;
import info.hexin.mvc.http.Http;
import info.hexin.mvc.methodtree.Arg;
import info.hexin.mvc.upload.TempFile;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * 文件上传
 * 
 * @author ydhexin@gmail.com
 * 
 */
public class FileUploadRequestProcess extends AbstractReequestProcess {
    private static final Log logger = Logs.get();

	@Override
	public void doMethodParam(HttpServletRequest request, HttpServletResponse response, List<Arg> args,
			List<Object> argList) throws IOException {
		String contentType = request.getContentType();
		logger.debug("getContentType >>> {}", request.getContentType());
		String bondary = Http.bondary(contentType);
		if (Strings.isBlank(bondary)) {
			throw new RuntimeException("request ContentType's  bondary is null !");
		}

		byte[] fileStartFlag = ("--" + bondary).getBytes();
		byte[] endNameFlag = "\n\r\n\r".getBytes();

		ServletInputStream inputStream = request.getInputStream();

		// 为了调用inputStream.available()
		int count = request.getContentLength();
		byte[] data = new byte[count];
		int readCount = 0;

		// 这里实现进度条
		int preReadSize = 1024 * 1024;// 1m

		while (readCount < count) {
			readCount = inputStream.read(data, readCount, count - readCount);
		}

		logger.debug(new String(data));
		List<TempFile> fileList = new ArrayList<TempFile>();

		TempFile tempFile = null;
		ByteBuffer fileNameBuffer = ByteBuffer.allocate(data.length);
		ByteBuffer fileContextBuffer = ByteBuffer.allocate(data.length);
		boolean inFileFlag = false;
		boolean inFileContextFlag = false;
		for (int i = 0, n = 0, k = 0; i < data.length; i++) {
			byte temp = data[i];
			// 第一次还没有进入file范围
			if (!inFileFlag) {
				// 查找file入口
				if (n < fileStartFlag.length && temp == fileStartFlag[n++]) {
					// 进入下一个阶段
					if (n == fileStartFlag.length) {
						// byte[] ii = new byte[6];
						// ii[0] = data[i - 5];
						// ii[1] = data[i - 4];
						// ii[2] = data[i - 3];
						// ii[3] = data[i - 2];
						// ii[4] = data[i - 1];
						// ii[5] = data[i - 0];
						// logger.debug(" n >>>> {} , will infile , end >>>> {}",
						// n, new String(ii));
						n = 0;
						inFileFlag = true;
					}
				}
			}
			// 进入文件内部
			else if (!inFileContextFlag) {

				// 查找file入口
				byte nameByte = endNameFlag[k++];
				if (k <= endNameFlag.length && temp == nameByte) {
					//
					// byte[] ii = new byte[6];
					// ii[0] = data[i - 5];
					// ii[1] = data[i - 4];
					// ii[2] = data[i - 3];
					// ii[3] = data[i - 2];
					// ii[4] = data[i - 1];
					// ii[5] = data[i - 0];
					// logger.debug(nameByte + " i >>>> " + i + " k >>>>" + k +
					// " ||| end >>>" + new String(ii));
					if (k + 1 == endNameFlag.length) {
						k = 0;
						byte[] fileNameByte = new byte[fileNameBuffer.position()];
						fileNameBuffer.rewind();
						fileNameBuffer.get(fileNameByte);
						fileNameBuffer.rewind();
						String fileName = new String(fileNameByte);
						tempFile = new TempFile(fileName);
						logger.debug("upload file name >>>>> {}", tempFile.getFileName());
						fileList.add(tempFile);
						inFileContextFlag = true;
					}
				}
				// 是否需要平移比如 nameend 但是"name"的end分隔符为 end，也就是说name的出现一样的byte需要平移
				else if (temp == endNameFlag[0]) {
					k = k - 1;
					fileNameBuffer.put(temp);
				} else {
					// 开始不需要回溯
					for (; k > 0; k--) {
						byte temp2 = data[i - k + 1];
						fileNameBuffer.put(temp2);
					}
					// inFileFlag = true;
				}
			} else {
				// 需要准备下一个文件域了
				// 查找file入口
				byte startFileChar = fileStartFlag[n++];
				if (n <= fileStartFlag.length && temp == startFileChar) {
					// 进入下一个阶段
					if (n == fileStartFlag.length) {
						n = 0;
						inFileFlag = true;
						inFileContextFlag = false;

						byte[] fileContextByte = new byte[fileContextBuffer.position()];
						fileContextBuffer.rewind();
						fileContextBuffer.get(fileContextByte);
						fileContextBuffer.rewind();
						// 文件内容
						logger.debug("===========文件内容  开始  ========= tempFile isFile >>> "+ tempFile.isFile());
						logger.debug(new String(fileContextByte));
						if (tempFile.isFile()) {
							tempFile.setFileByte(fileContextByte);
						}
						logger.debug("===========文件内容  结束  ========= tempFile isFile >>> "+ tempFile.isFile());
					}
				} else {
					fileContextBuffer.put(temp);
					n = 0;
				}
			}
		}

		// 开始封装参数
		String requestUrl = request.getRequestURI();
		String tempRequestUrl = requestUrl.substring(1);
		String[] urls = tempRequestUrl.split("/");
		for (Arg arg : args) {
			Class<?> argAnClazz = arg.getAnClass();
			if (argAnClazz == null) {
				Class<?> paramClass = arg.getParamClass();
				if (paramClass == HttpServletRequest.class) {
					argList.add(request);
				} else if (paramClass == HttpSession.class) {
					argList.add(request.getSession());
				} else if (paramClass == HttpServletResponse.class) {
					argList.add(response);
				}
			} else {
				String paramName = arg.getName();
				if (argAnClazz == HeaderParam.class) {
					String value = request.getHeader(paramName);
					argList.add(value);
				} else if (argAnClazz == Param.class) {
					String value = request.getParameter(paramName);
					argList.add(value);
				} else if (argAnClazz == PathParam.class) {
					int i = arg.getPathIndex();
					String pathValue = urls[i];
					argList.add(pathValue);
				} else if (argAnClazz == MultiFile.class) {
					String formName = arg.getName();
					if ("".equals(formName)) {
						for (TempFile t : fileList) {
							if (t.isFile()) {
								logger.debug("MultiFile value is null, get request upload file >>> " + t.getFileName());
								argList.add(t);
							}
						}
					} else {
						for (TempFile t : fileList) {
							if (t.isFile()) {
								t.getFormName().equals(formName);
								argList.add(t);
							}
						}
					}
				}
			}
		}
	}
}
